/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package org.apache.airavata.metcat.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXNodeEventHandler extends DefaultHandler {

	private final String WORKFLOW_EVENT_SCHEMA = "http://airavata.apache.org/schemas/workflow_tracking_types";
	
	private Map<String, List<IndexAttribute>> metadataIndices = null;
	private Map<String, String> result = new HashMap<String, String>();
	
	private boolean inschema = false;
	private String prefix = null;
	private String insideTag = null;
	private IndexAttribute insTag = null;
	private StringBuilder sb = null;
	
	private String depth = "/";
	
	public SAXNodeEventHandler(Map<String, List<IndexAttribute>> metadataIndices) {
		this.metadataIndices = metadataIndices;
	}
	
	private List<IndexAttribute> findList() {
		List<IndexAttribute> list = new ArrayList<IndexAttribute>();
		
		int pos = -1;
		for (IndexAttribute attr : this.metadataIndices.get(prefix)) {
			if (attr.getXPath().equals(depth)) {
				attr.setTag(0);
				list.add(attr);
				continue;
			}
			
			pos = attr.getXPath().lastIndexOf("/@");
			if (pos < 0) continue;
			String temp = attr.getXPath().substring(0, pos);
			if (temp.equals(depth)) {
				list.add(attr);
				attr.setTag(1);
			}
		}
		
		return list;
	}
	
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if (!inschema) return;
		
		depth = depth + "/" + localName;
		
		List<IndexAttribute> fattr = this.findList();
		if (fattr.size() <= 0) return;
		
		for (IndexAttribute attr : fattr) {
			if (attr.getTag() == 1) {
				int pos = attr.getXPath().lastIndexOf("/@");
				String attrname = attr.getXPath().substring(pos + 2);
				
				this.result.put(attr.getLabel(), attributes.getValue(attrname)); 
				this.insideTag = null;
				this.insTag = null;
			} else {
				this.insideTag = localName;
				this.insTag = attr;
				this.sb = new StringBuilder();
			}
		}
		
	}
	
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if (insideTag == null || this.insTag == null) return;
		
		sb.append(new String(ch, start, length));
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (!inschema) return;

		int pos = depth.lastIndexOf("/");
		if (pos < 0) return;
		String lname = depth.substring(pos + 1);
		if (localName.equals(lname)) {
			depth = depth.substring(0, pos);
		}
		
		if (this.insideTag != null && this.insTag != null) {
			if (localName.equals(this.insideTag)) {
				this.result.put(this.insTag.getLabel(), this.sb.toString());
				this.insideTag = null;
				this.insTag = null;
				this.sb = null;
			}
		}
	}
	
	@Override
	public void startPrefixMapping(String prefix, String uri) throws SAXException {
		if (uri.equals(WORKFLOW_EVENT_SCHEMA)) {
			inschema = true;
			this.prefix = prefix;
		}
	}
	
	@Override
	public void endPrefixMapping(String prefix) throws SAXException {
		if (this.prefix == prefix) {
			prefix = null;
			inschema = false;
		}
	}
	
	public Map<String, String> getResult() {
		return result;
	}
	
	public void setResult(Map<String, String> result) {
		this.result = result;
	}
	
	public void setMetadataIndices(Map<String, List<IndexAttribute>> metadataIndices) {
		this.metadataIndices = metadataIndices;
	}
	
}
